package com.example.video;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.highgui.Highgui;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;

import com.example.audio.Audio;
import com.example.audio.AudioOut;
import com.example.controller.MainActivity;
import com.example.listenanddriveproject.R;

public class VideoFragment extends Fragment implements CvCameraViewListener2 {

    private CameraBridgeViewBase mOpenCvCameraView;		//Gestion de la caméra
    private boolean mIsJavaCamera = true;
    private MenuItem mItemSwitchCamera = null;
    public View rootView;
    private int mViewMode;
    private int	mHeight;		//Résolution "hauteur" de la caméra
    private int	mWidth;			//Résolution "largeur" de la caméra
    private float ratio;			//Ratio pour le son.
    private Mat mRgb;				//Matrice couleur "Input"
    private Mat mGrayMat;			//Matrice output, de base en niveau de gris
    private Audio mAudio;			//Audio gestion du son
    private AudioOut audioOut;		//Audio gestion du "bip"
    private int cpt;				//Compteur pour la gestion du bip, compte le nombre de fois d'anomalie dans la detection de balise (Différences de tailles, pas de balises détéctée, etc)
    private int tableau[];			//Tableau de la remise à plat d'une capture "Fish eye", "Optimisation grand angle".
    private int SettingsArray[];	//Tableau qui récupére les settings, pratique pour les renvoyer vers la "zone native".

    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(getActivity()) {
        @Override
        public void onManagerConnected(int status) {
        	switch (status) {
            case LoaderCallbackInterface.SUCCESS:
            {
                // Load native library after(!) OpenCV initialization
                System.loadLibrary("mixed_sample");	//Chargement de la partie C++
            
                mOpenCvCameraView.enableView();	//Activation de la caméra
            } break;
            default:
            {
                super.onManagerConnected(status);
            } break;
        }
        }
    };
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
 
        rootView = inflater.inflate(R.layout.tutorial1_surface_view, container, false);
        
        getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

       // getActivity().setContentView(R.layout.tutorial1_surface_view);

        if (mIsJavaCamera)
            mOpenCvCameraView = (CameraBridgeViewBase) rootView.findViewById(R.id.tutorial1_activity_java_surface_view);
       /* else
            mOpenCvCameraView = (CameraBridgeViewBase) rootView.findViewById(R.id.tutorial1_activity_native_surface_view);*/

        mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);

        mOpenCvCameraView.setCvCameraViewListener(this);	//Activation de la vue de la caméra
        mOpenCvCameraView.setMaxFrameSize(700, 700);		//Reglage de la résolution maximale
        mOpenCvCameraView.setMinimumHeight(200);			//Réglage de la résolution minimale
        mOpenCvCameraView.setMinimumWidth(200);				//Réglage de la résolution minimale
        mOpenCvCameraView.SetCaptureFormat(Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);	//Format de capture de la caméra en Rgba (Couleur)
        
        mAudio=new Audio(this.getActivity());	//Activation de la gestion du son
        audioOut=new AudioOut(this.getActivity());	//Activation de la gestion du "bip"
        audioOut.startSound();
        
        cpt=0;		//Initialisation du compteur du bip
        
        return rootView;
    }

    /***
     * Procedure pour remettre a plat une capture effet "fish eyes"
     */
    public void CalcMorpho()
    {
        double paramA = -SettingsArray[0]/100000; // affects only the outermost pixels of the image -0.007715
        double paramB = SettingsArray[1]/100000; // most cases only require b optimization 0.026731
        double paramC = 0.0; // most uniform correction
        double paramD;
        int d;    // radius of the circle
        // center of dst image
	    double centerX;
	    double centerY;
	    // cartesian coordinates of the destination point (relative to the centre of the image)
	    double deltaX;
	    double deltaY;
	    // distance or radius of dst image
	    double dstR;
	    // distance or radius of src image (with formula)
	    double srcR;
	    // comparing old and new distance to get factor
	    double factor;
	    // coordinates in source image
	    double srcXd;
	    double srcYd;
	    // no interpolation yet (just nearest point)
	    int srcX;
	    int srcY;
	
	    paramD = 1.0 - paramA - paramB - paramC; // describes the linear scaling of the image
	    d = Math.min(mWidth, mHeight) / 2;    // radius of the circle
	    // center of dst image
	    centerX = (mWidth - 1) / 2.0;
	    centerY = (mHeight - 1) / 2.0;
	        for (int x = 0; x < mWidth; x++) {
	    		for (int y = 0; y < mHeight; y++) 
	    		{
		    		// cartesian coordinates of the destination point (relative to the centre of the image)
		    		deltaX = (x - centerX) / d;
		    		deltaY = (y - centerY) / d;
		
		    		// distance or radius of dst image
		    		dstR = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
		
		    		// distance or radius of src image (with formula)
		    		srcR = (paramA * dstR * dstR * dstR + paramB * dstR * dstR + paramC * dstR + paramD) * dstR;
		
		    		// comparing old and new distance to get factor
		    		factor = Math.abs(dstR / srcR);
		
		    		// coordinates in source image
		    		srcXd = centerX + (deltaX * factor * d);
		    		srcYd = centerY + (deltaY * factor * d);
		
		    		// no interpolation yet (just nearest point)
		    		srcX = (int)(srcXd);
		    		srcY = (int)(srcYd);
		
		    		if (srcX >= 0 && srcY >= 0 && srcX < mWidth && srcY < mHeight) 
		    		{
			    		//valeur de X et Y
			    		tableau[y*mWidth+x]=srcX;
			    		tableau[y*mWidth+x+mWidth*mHeight]=srcY;
		    		}
	    		}
	        }
    	
    }
    
    @Override
    public void onPause()
    {
        super.onPause();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
        mAudio.close();	//Pause de l'audio
        audioOut.pauseSound();
    }
    
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);

        // Make sure that we are currently visible
        if (this.isVisible()) {
            // If we are becoming invisible, then...
            if (!isVisibleToUser) {
            	if (mOpenCvCameraView != null)
                    mOpenCvCameraView.disableView();
                mAudio.close();	//Pause de l'audio
                audioOut.pauseSound();
            }
            if (isVisibleToUser) {
            	OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_7, getActivity(), mLoaderCallback);
            	mAudio=new Audio(this.getActivity());	//Activation de la gestion du son
            }
        }
    }

    @Override
    public void onResume()
    {
        super.onResume();
        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_7, getActivity(), mLoaderCallback);
    }

    public void onDestroy() {
        super.onDestroy();
        mAudio.close();	//Destruction de l'audio
        audioOut.stopSound();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
        
    }
    
    public void onCameraViewStarted(int width, int height) {
    	mWidth=width;	//Récuperation de la résolution de capture
    	mHeight=height;
        mRgb = new Mat(height, width, CvType.CV_8UC3);		//Matrice "Input"

        mGrayMat = new Mat(height, width, CvType.CV_8UC1); //Matrice "Output"
        tableau =new int[(width*height*2)];					//Initialisation du tableau des settings
        SettingsArray=MainActivity.settings.getArray();
        CalcMorpho();										//Calcul de la mise à plat.
    }

    public void onCameraViewStopped() {
    	mRgb.release();
        mGrayMat.release();
    }

	@Override
	public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
		
		mRgb=inputFrame.rgba();	//Récuperation d'une frame couleur

        //  Imgproc.cvtColor(mRgb, mRgb, Imgproc.COLOR_BGR2GRAY, 3);
        
        SettingsArray=MainActivity.settings.getArray();
        
        if(SettingsArray[15]>0)	//Calcul de la mise à plat si les settings ont été modifiés
        {
        	CalcMorpho();
        	MainActivity.settings.setChange(0);
        }
        //Passage sur le traitement d'image en C++...ratio nous donne le ratio pour le son
        ratio=FindFeatures(mRgb.getNativeObjAddr(), mGrayMat.getNativeObjAddr(), mWidth, mHeight,tableau,SettingsArray);
        
		/*
		  Les parametres envoyés sont...L'input (Image couleur)
		  Output, la sortie de même resolution que l'image couleur
		  La résolution
		  Le tableau de la mise à plat du fish eye
		  Le tableau des settings
		  */      
		        
        //Si ratio=404, un problème a été detecté parmis les balises (Non trouvée, deux balises du même coté...)...Incrémentation du compteur pour le bip et conservation du ratio précédent.
        if(ratio!=404){	//Normal, on change la balance stéréo en fonction de ce qui a été détécté.
        	mAudio.returnAudio(ratio);
        	cpt=0;
        	audioOut.pauseSound();
        }else{		//Anomalie, on incrémente le compte et conserve la balance stéréo précédente, si celui-ci a une valeur trop élevée, on bip
        	cpt++;
        	if(cpt>12){
            	audioOut.startSound();
            	audioOut.checkHeadSet();
            }
        }
           if(SettingsArray[12]>0)
        {return mGrayMat;}
           return null;
	}
		
    public native float FindFeatures(long matAddrRgba,long matAddrOutput, int width, int height,int[] tableau,int[] SettingsArray);

}
